#import "ALAttachmentElementColumnEntry.h"
#import "NSObject+BlockObservation.h"
#import "NSManagedObject+SMRAdditions.h"
#import "NSImage+SMRAdditions.h"
#import "ALElement.h"
#import "SMRBorderFrameLine.h"
#import "SMRBorderFrameSunkenRounded.h"


#pragma mark Constants

static const CGFloat ALAttachmentElementMinimumViewHeight = 35.0f;
static const CGFloat ALAttachmentElementDefaultViewHeight = 80.0f;
static const CGFloat ALAttachmentElementMaximumImageHeight = 200.0f;
static const CGFloat ALAttachmentElementBorderFramePopUpImageHeight = 50.0f;
static const ALBorderFrameTag ALImageElementDefaultBorderFrameTag = ALBorderFrameLine;
static NSString* const ALAttachmentElementDefaultImageName = @"angelImageDesaturated.png";
static NSString* const ALAttachmentBorderFrameTagKey = @"attachmentBorderFrameTag";
static NSString* const ALAttachmentElementViewHeightKey = @"viewHeight";
static NSString* const ALAttachmentElementBorderFrameTagKey = @"attachmentBorderFrameTag";
static NSString* const ALAttachmentElementImageKey = @"attachmentImage";


#pragma mark -
#pragma mark Class globals
static NSImage *ALImageElementDefaultImage;
static NSDictionary *ALBorderFrameClassDictionary;


#pragma mark -
@interface ALAttachmentElementColumnEntry ()
@property (nonatomic, retain) NSOperationQueue *imageOperationQueue;
@property (nonatomic, assign) CGFloat imageViewPadding;
@end


#pragma mark -
@interface ALAttachmentElementColumnEntry (ALAttachmentElementColumnEntryPrivateMethods)
-(ALBorderFrameTag)persistedBorderFrameTag_;
-(void)setPersistedBorderFrameTag_:(ALBorderFrameTag)borderTag;
-(NSString *)attachmentBorderFrameKey;
-(SMRBorderFrame *)borderFrameWithTag_:(ALBorderFrameTag)borderTag;
-(CGFloat)persistedViewHeight_;
-(void)setPersistedViewHeight_:(CGFloat)newImageHeight;
-(NSString *)persistedViewHeightKey;
@end


#pragma mark -
@implementation ALAttachmentElementColumnEntry

@synthesize borderFramePopup;
@synthesize valueView;
@synthesize imageOperationQueue;
@synthesize attachmentBorderFrameTag;
@synthesize viewHeight;
@synthesize imageViewPadding;


+(void)initialize {
	ALBorderFrameClassDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[SMRBorderFrameLine class], [NSNumber numberWithInteger:ALBorderFrameLine], [SMRBorderFrameSunkenRounded class], [NSNumber numberWithInteger:ALBorderFrameSunkenRounded], nil];
	
	NSURL *defaultImageURL = [[NSBundle mainBundle] URLForImageResource:ALAttachmentElementDefaultImageName];
	if (!defaultImageURL)
		return;
	ALImageElementDefaultImage = [[NSImage alloc] initWithContentsOfURL:defaultImageURL];
}

-(void)awakeFromNib {
	[self setImageOperationQueue:[[NSOperationQueue alloc] init]];
	
	CGFloat imageViewHeight = [[self valueView] frame].size.height;
	CGFloat elementViewHeight = [[self view] frame].size.height;
	[self setImageViewPadding:elementViewHeight - imageViewHeight];
	
	NSRect borderFramePopupRect = [[self borderFramePopup] frame];
	borderFramePopupRect.size.height = ALAttachmentElementBorderFramePopUpImageHeight;
	[[self borderFramePopup] setFrame:borderFramePopupRect];
	
	AMBlockTask imageTask = ^(id object, NSDictionary *change) {
		NSURL *attachmentURL = [[self representedObject] attachmentURL];
		if (!attachmentURL) {
			[[self representedObject] setAttachmentImage:ALImageElementDefaultImage];
			return;
		}		
		[[self imageOperationQueue] addOperationWithBlock:^ {
			NSSize maxSize = NSMakeSize(CGFLOAT_MAX, ALAttachmentElementMaximumImageHeight);
			NSImage *quickLookImage = [NSImage thumbnailImageFromURL:attachmentURL withMaximumSize:maxSize asIcon:NO];
			[[self representedObject] performSelectorOnMainThread:@selector(setAttachmentImage:) withObject:quickLookImage waitUntilDone:NO];
		}];
	};
	NSString *imageKey = [NSString stringWithFormat:@"%@.%@", ALRepresentedObjectKey, ALAttachmentURLStringKey];
	[self addObserverForKeyPath:imageKey task:imageTask];
	
	AMBlockTask borderFrameTask = ^(id object, NSDictionary *change) {
		ALBorderFrameTag borderTag = [self persistedBorderFrameTag_];
		if (borderTag == ALBorderFrameUnknown)
			borderTag = ALImageElementDefaultBorderFrameTag;
		SMRBorderFrame *borderFrame = [self borderFrameWithTag_:borderTag];
		[[self valueView] setBorderFrame:borderFrame];
		[self setAttachmentBorderFrameTag:borderTag];
	};
	[self addObserverForKeyPath:ALRepresentedObjectKey task:borderFrameTask];
}


#pragma mark -
#pragma mark Actions

-(IBAction)chooseFile:(id)sender {
	NSOpenPanel *openPanel = [NSOpenPanel openPanel];
	[openPanel setAllowsMultipleSelection:NO];
	[openPanel beginWithCompletionHandler:^(NSInteger result) {
		if (result != NSFileHandlingPanelOKButton)
			return;
		NSArray *selectedURLs = [openPanel URLs];
		if ([selectedURLs count] == 0)
			return;
		NSURL *firstURL = [selectedURLs objectAtIndex:0];
		[[self representedObject] setAttachmentURL:firstURL];
	}];
}


#pragma mark -
#pragma mark Column entry overrides

-(void)columnEntryWasAddedToColumnView {
	[super columnEntryWasAddedToColumnView];
	AMBlockTask borderFrameTagTask = ^(id object, NSDictionary *change) {
		ALBorderFrameTag borderTag = [self attachmentBorderFrameTag];
		SMRBorderFrame *borderFrame = [self borderFrameWithTag_:borderTag];
		[[self valueView] setBorderFrame:borderFrame];
		[self setPersistedBorderFrameTag_:borderTag];
	};
	[self addObserverForKeyPath:ALAttachmentBorderFrameTagKey task:borderFrameTagTask];
	
	CGFloat persistedViewHeight = [self persistedViewHeight_];
	if (persistedViewHeight == CGFLOAT_MAX)
		persistedViewHeight = fmin(ALAttachmentElementDefaultViewHeight, [self maxViewHeight]);
	[self setViewHeight:persistedViewHeight];
	
	AMBlockTask viewHeightTask = ^(id object, NSDictionary *change) {
		[self setPersistedViewHeight_:[self viewHeight]];
		[[self columnView] layoutWithAnimation:NO];
	};
	[self addObserverForKeyPath:ALAttachmentElementViewHeightKey task:viewHeightTask];
}

-(void)columnEntryDidBeginEditingAtPoint:(NSPoint)aPoint {
	[[self valueView] setEditable:YES];
//	[[self valueView] showEditModeBezel];
	[super columnEntryDidBeginEditingAtPoint:aPoint];
}

-(void)columnEntryDidEndEditing {
	[[self valueView] setEditable:NO];
//	[[self valueView] hideEditModeBezel];
	[super columnEntryDidEndEditing];
}

-(CGFloat)preferredHeightForWidth:(CGFloat)width {
	return [self viewHeight];
}


#pragma mark -
#pragma mark Border frame persistence

-(ALBorderFrameTag)persistedBorderFrameTag_ {
	NSNumber *borderTagNumber = [[NSUserDefaults standardUserDefaults] objectForKey:[self attachmentBorderFrameKey]];
	if (borderTagNumber)
		return (ALBorderFrameTag)[borderTagNumber integerValue];
	return ALBorderFrameUnknown;
}

-(void)setPersistedBorderFrameTag_:(ALBorderFrameTag)borderTag {
	[[NSUserDefaults standardUserDefaults] setInteger:borderTag forKey:[self attachmentBorderFrameKey]];
}

-(NSString *)attachmentBorderFrameKey {
	return [NSString stringWithFormat:@"%@.borderFrameTag", [[self representedObject] smrURIRepresentation]];
}

-(SMRBorderFrame *)borderFrameWithTag_:(ALBorderFrameTag)borderTag {
	Class borderFrameClass = [ALBorderFrameClassDictionary objectForKey:[NSNumber numberWithInteger:borderTag]];
	if (!borderFrameClass)
		return nil;
	SMRBorderFrame *borderFrame = [[borderFrameClass alloc] init];
	return borderFrame;
}


#pragma mark -
#pragma mark Value view resizing

-(void)setViewHeight:(CGFloat)height {
	viewHeight = floor(height);
}

-(CGFloat)persistedViewHeight_ {
	NSNumber *persistedViewHeight = [[NSUserDefaults standardUserDefaults] objectForKey:[self persistedViewHeightKey]];
	if (!persistedViewHeight)
		return CGFLOAT_MAX;
	return [persistedViewHeight floatValue];
}

-(void)setPersistedViewHeight_:(CGFloat)newViewHeight {
	[[NSUserDefaults standardUserDefaults] setFloat:newViewHeight forKey:[self persistedViewHeightKey]];
}

-(NSString *)persistedViewHeightKey {
	return [NSString stringWithFormat:@"%@.attachmentViewHeight", [[self representedObject] smrURIRepresentation]];
}

+(NSSet *)keyPathsForValuesAffectingMaxViewHeight {
	NSString *attachmentImageKey = [NSString stringWithFormat:@"%@.%@", ALRepresentedObjectKey, ALAttachmentElementImageKey];
	return [NSSet setWithObjects:ALAttachmentElementBorderFrameTagKey, attachmentImageKey, nil];
}

-(CGFloat)maxViewHeight {
	// First get max image height
	NSImage *image = [(ALElement *)[self representedObject] attachmentImage];
	NSSize imageSize = [image size];
	CGFloat maxHeight = fmax(imageSize.height, ALAttachmentElementMinimumViewHeight);
	maxHeight = fmin(maxHeight, ALAttachmentElementMaximumImageHeight);
	
	// Add padding around image view inside element view
	maxHeight += [self imageViewPadding];
	
	SMRBorderFrame *borderFrame = [[self valueView] borderFrame];
	if (!borderFrame)
		return maxHeight;
	// Add padding for current border frame
	maxHeight += [borderFrame verticalPadding];
	return maxHeight;
}

-(CGFloat)minViewHeight {
	return ALAttachmentElementMinimumViewHeight;
}

@end
